package com.gmrz.uas.plugin.sm2;

import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.CertificationRequest;
import org.bouncycastle.asn1.pkcs.CertificationRequestInfo;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;

import javax.security.auth.x500.X500Principal;
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.*;

/**
 * Created by zhangchao on 4/11/18.
 */
public class SM2PKCS10Utils {

    public static byte[] pubkey;
    public static class P10Info{
        public String CN = null;
        public String OU = null;
        public String ID = null;
    }

    public static PKCS10CertificationRequest createSM2P10(String dn, final Sm2KeyPair pair) throws Exception{
        pubkey = pair.getPubKey();
        X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE);
        String[] dns = dn.split(",");
        Field[] fields = BCStyle.class.getFields();
        for(String rdn : dns){
            String[] rdns = rdn.split("=");
            for(Field field : fields){
                String fieldName = field.getName();
                if(rdns[0].equals(fieldName)){
                    x500NameBld.addRDN((ASN1ObjectIdentifier) field.get(BCStyle.class),rdns[1]);
                }
            }
        }

//        Field[] fields = BCStyle.class.getFields();
//        x500NameBld.addRDN(BCStyle.CN, info.CN);
//        x500NameBld.addRDN(BCStyle.OU, info.OU);
  //      x500NameBld.addRDN(BCStyle.UNIQUE_IDENTIFIER, info.ID);
        X500Name subject = x500NameBld.build();

        Extension[] extSigning = new Extension[] {
                new Extension(Extension.basicConstraints, true, new DEROctetString(new BasicConstraints(true))),
                new Extension(Extension.keyUsage, true, new DEROctetString(new KeyUsage(KeyUsage.keyCertSign))),
        };

        byte[] pubkey = new byte[65];
        pubkey[0] = 0x04;
        System.arraycopy(pair.getPubKey(),0,pubkey,1,64);
        SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo(SM2.SM2_ALOGITHM_IDENTIFIER,pubkey);
        PKCS10CertificationRequestBuilder builder = new PKCS10CertificationRequestBuilder(subject, publicKeyInfo).addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, new Extensions(extSigning));
        PKCS10CertificationRequest req = builder.build(new SM2ContentSigner(pair.getPriKey()));

        return req;
    }

    public static boolean verifySM2P10(PKCS10CertificationRequest p10CSR){
        CertificationRequest requestASN1 =  p10CSR.toASN1Structure();
        byte[] data = new byte[0];
        try {
            data = requestASN1.getCertificationRequestInfo().getEncoded(ASN1Encoding.DER);
            byte[] signature = p10CSR.getSignature();
            byte[] pubkey = requestASN1.getCertificationRequestInfo().getSubjectPublicKeyInfo().getPublicKeyData().getBytes();
            byte[] pubkeyraw = new byte[64];
            System.arraycopy(pubkey,1,pubkeyraw,0,64);
            boolean verifyResult = SM2Utils.verifySign(pubkeyraw,data,signature);
            if(!verifyResult){
                System.out.print("sign cert failed");
                return false;
            }else{
                System.out.print("sign cert success\n");
                return true;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    public static PKCS10CertificationRequest createRSAP10(String dn,KeyPair keyPair) {
        try {
            PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(
                    new X500Principal(dn), keyPair.getPublic());
            JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256withRSA");
            ContentSigner signer = csBuilder.build(keyPair.getPrivate());
            PKCS10CertificationRequest csr = p10Builder.build(signer);
            return csr;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static KeyPair getKey() throws Exception{
        KeyPairGenerator ecPair = KeyPairGenerator.getInstance("RSA", "BC");
        ecPair.initialize(2048, new SecureRandom()); // keyPair密钥对KeyPair keyPair2 = ecPair.generateKeyPair();
        KeyPair keyPair = ecPair.generateKeyPair();
        return keyPair;
    }

    public static void main(String[] args) throws Exception {
//        SM2PKCS10Utils.P10Info info = new SM2PKCS10Utils.P10Info();
//        info.CN = "GMRZ";
//        info.ID = "123456";
//        info.OU = "123456";
//
//        Sm2KeyPair keyPair = SM2Utils.generateKeyPair();
//        System.out.println("keypair:"+ Convert.toBase64(keyPair.getPubKey())+","+Convert.toBase64(keyPair.getPriKey()));
//        PKCS10CertificationRequest request = SM2PKCS10Utils.createSM2P10("CN=GMRZ;OU=123456;UNIQUE_IDENTIFIER=123456",keyPair);
//        System.out.println(verifySM2P10(request));

        //System.out.println("dn:"+Convert.toBase64("CN=GMRZ,OU=123456".getBytes("UtF-8")));
    }
}
